﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Microsoft.Windows.Controls;
using System.Collections.ObjectModel;
using System.Windows.Threading;
using System.ComponentModel;
using System.Globalization;
using ResourceBlender.Core;

namespace ResourceBlender.Express {
    /// <summary>
    /// Allows elements to be added in bulk.
    /// </summary>
    public partial class WinBulkAddElements : Window {
        private ObservableCollection<PendingTranslation> elements;

        /// <summary>
        /// Gets a list of elements the user entered.
        /// </summary>
        /// <value>The elements.</value>
        public ICollection<string> Elements {
            get {
                return (from element in elements
                       where element.Translation.Trim().Length > 0
                       select element.Translation).ToList();
            }
        }

        /// <summary>
        /// Gets the language code of the elements entered.
        /// </summary>
        /// <value>The language code of the elements.</value>
        public string ElementLanguage {
            get { return cboLanguage.SelectedValue.ToString(); }
        }

        /// <summary>
        /// Gets the ID of the bundle to which to add the elements.
        /// </summary>
        /// <value>The ID of the bundle to which to add the elements.</value>
        public string Bundle {
            get { return cboBundle.SelectedValue.ToString(); }
        }

        /// <summary>
        /// Initializes a new <see cref="WinBulkAddElements"/>.
        /// </summary>
        public WinBulkAddElements(ObservableApplication app) {// List<string> languages, string defaultLanguage, ObservableSortedDictionary<string, string> bundles) {
            InitializeComponent();
            if(app.Bundles.Count == 0) {
                throw new ResourceBlenderException("Application contains no bundles");
            }
            elements = new ObservableCollection<PendingTranslation>();
            /*elements.Add(new PendingTranslation("Somehow Visual Studio doesn't come with an option to only auto increment the build version of the AssemblyFileVersion attribute."));
            elements.Add(new PendingTranslation("C#, VB.NET and C++.NET"));
            elements.Add(new PendingTranslation("Iñtërnâtiônàlizætiøn"));
            elements.Add(new PendingTranslation("Русский,使用偏好,プライバシ"));*/
            dgResources.ItemsSource = elements;
            DataContext = app;
            ObservableSortedDictionary<string, CultureInfo> selectedLangs = new ObservableSortedDictionary<string, CultureInfo>(new Comparers.CultureInfoEnglshNameComparer(), new Comparers.StringEqualityComparer());
            foreach(string selectedCode in app.Languages) {
                CultureInfo info = Utils.GetCultureInfo(selectedCode);
                if(info != null) {
                    selectedLangs.Add(selectedCode, info);
                }
            }
            cboLanguage.ItemsSource = selectedLangs;
            cboBundle.SelectedIndex = 0;
        }

        /// <summary>
        /// Focuses the next row when enter or return is pressed
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="Microsoft.Windows.Controls.DataGridRowEditEndingEventArgs"/> instance containing the event data.</param>
        private void dgResources_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e) {
            if(e.EditAction == DataGridEditAction.Commit && dgResources.SelectionUnit == DataGridSelectionUnit.Cell) {
                if(Keyboard.IsKeyDown(Key.Enter) || Keyboard.IsKeyDown(Key.Return)) {
                    // get the row and column indexes of the currently selected cell
                    int currentColIndex = dgResources.Columns.IndexOf(dgResources.CurrentColumn),
                        currentRowIndex = dgResources.Items.IndexOf(e.Row.Item);
                    var rowToSelect = dgResources.Items[currentRowIndex + 1]; // get the next row
                    var colToSelect = dgResources.Columns[currentColIndex];
                    int rowIndex = dgResources.Items.IndexOf(rowToSelect);
                    // select the new cell
                    dgResources.SelectedCells.Clear();
                    dgResources.SelectedCells.Add(new DataGridCellInfo(rowToSelect, colToSelect));
                    this.Dispatcher.BeginInvoke(new DispatcherOperationCallback((param) => {
                        // get the new cell, set focus, then open for edit
                        var cell = DataGridUtils.GetCell(dgResources, rowIndex, currentColIndex);
                        cell.Focus();
                        dgResources.BeginEdit();
                        return null;
                    }), DispatcherPriority.Background, new object[] { null });
                }
            }
        }

        /// <summary>
        /// Focuses and selects all text in the TextBox used for editing when it is selected.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void txt_Initialized(object sender, EventArgs e) {
            TextBox tb = sender as TextBox;
            if(tb != null) {
                tb.Focus();
                tb.SelectAll();
            }
        }

        /// <summary>
        /// Always allows a command to execute.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
        private void CanAlwaysExecute(object sender, CanExecuteRoutedEventArgs e) {
            e.CanExecute = true;
        }

        private void AddElement(object sender, ExecutedRoutedEventArgs e) {
            int colIndex = 0;
            var rowToSelect = dgResources.Items[dgResources.Items.Count - 1];
            var colToSelect = dgResources.Columns[colIndex];
            int rowIndex = dgResources.Items.IndexOf(rowToSelect);
            // select the new cell
            dgResources.SelectedCells.Clear();
            dgResources.SelectedCells.Add(new DataGridCellInfo(rowToSelect, colToSelect));
            this.Dispatcher.BeginInvoke(new DispatcherOperationCallback((param) => {
                // get the new cell, set focus, then open for edit
                var cell = DataGridUtils.GetCell(dgResources, rowIndex, colIndex);
                cell.Focus();
                dgResources.BeginEdit();
                return null;
            }), DispatcherPriority.Background, new object[] { null });
        }

        /// <summary>
        /// Deletes the selected resource.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void DeleteElement(object sender, ExecutedRoutedEventArgs e) {
            if(dgResources.SelectedCells.Count == 0)
                return;
            if(DialogBox.Show(this, "Delete element?", "Confirm Deletion", DialogBox.DialogBoxType.YesNo, DialogBox.DialogBoxIcon.Question, DialogBox.DialogBoxButton.No) == DialogBox.DialogBoxButton.Yes) {
                PendingTranslation selectedValue = dgResources.SelectedCells[0].Item as PendingTranslation;
                elements.Remove(selectedValue);
            }
        }

        /// <summary>
        /// Returns a DialogResult of true and closes the window.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void Save(object sender, ExecutedRoutedEventArgs e) {
            this.DialogResult = true;
            Close();
        }

        /// <summary>
        /// Opens the help file.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void ShowHelp(object sender, ExecutedRoutedEventArgs e) {
            WPFUtils.OpenHelp("Translating.an.Application.html#bulkadd");
        }

        /// <summary>
        /// Closes the window.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void CloseWindow(object sender, ExecutedRoutedEventArgs e) {
            Close();
        }

        /// <summary>
        /// Simplifies binding translations to the DataGrid
        /// </summary>
        private class PendingTranslation : INotifyPropertyChanged {
            private string translation;
            public string Translation {
                get { return translation; }
                set { 
                    translation = value;
                    OnPropertyChanged("Translation");
                }
            }

            public PendingTranslation() {
                this.translation = string.Empty;
            }
            public PendingTranslation(string translation) {
                this.translation = translation;
            }

            public event PropertyChangedEventHandler PropertyChanged;
            protected virtual void OnPropertyChanged(string strPropertyName) {
                if(PropertyChanged != null) {
                    PropertyChanged(this, new PropertyChangedEventArgs(strPropertyName));
                }
            }
        }
    }
}
